/** @file    AutomationDeviceLink.cpp
 *  @author  Alessandro Polo
 *  @version $Id: AutomationDeviceLink.cpp 2084 2010-03-11 10:49:02Z alex $
 *  @brief
 * File containing methods for the wosh::automations::AutomationDeviceLink class.
 * The header for this class can be found in AutomationDeviceLink.h, check that file
 * for class description.
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/
 
 #include <framework/automations/AutomationDeviceLink.h>

 #include <core/MethodsDef.h>
 #include <core/Bus.h>
 #include <core/Fact.h>


namespace wosh {
 namespace automations {

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////// CONSTRUCTORS

AutomationDeviceLink::AutomationDeviceLink() : Automation()
 {
	Automation::setName("AutomationDeviceLink", this->uid);

	Log.setContext( Object::getName() );
 }

AutomationDeviceLink::AutomationDeviceLink( const AutomationDeviceLink& m ) : Automation(m)
 {
	*this = m;
 }

AutomationDeviceLink::~AutomationDeviceLink()
 {
	Log(LOG_VERBOSE, ":~AutomationDeviceLink() : Destroying.." );

 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

WRESULT AutomationDeviceLink::execute( const Message* message, int64 )
 {
	DeviceEffect* effect = getEffect_( message );
	if ( effect == NULL )
		return WRET_ERR_PARAM;

	Message* msg_effect = effect->generateMessage();
	msg_effect->setSource( this );
	msg_effect->setDestinationBus( _Bus_Devices );

	WRESULT ret = postMessage(msg_effect);
	return ret;
 }

bool AutomationDeviceLink::isTrigger( const Message* message, int64 ) const
 {
	if ( message == NULL ) return false;
	DeviceEffect* effect = getEffect_( message );
	if ( effect == NULL )
		return false;
	return true;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

DeviceEffect* AutomationDeviceLink::getEffect_( const Message* message ) const
 {
	if ( message == NULL || message->isEmpty() ) return NULL;
	if ( !message->getContent()->isFact() )  return NULL;
	const Fact* fact = message->getContent()->asFact();

	bool found = false;
	std::map<DeviceTrigger*, DeviceEffect*>::const_iterator it;
	for(it=this->mappings.begin(); it!=this->mappings.end(); it++) {
		if ( it->first == NULL ) continue;
		found = it->first->compare(message->getSource(), fact);
		if ( found )
			return it->second;
	 }
	return NULL;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

WRESULT AutomationDeviceLink::addMapping( DeviceTrigger* fact_data, DeviceEffect* request_data )
 {
	this->mappings[fact_data] = request_data;
	return WRET_OK;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

AutomationDeviceLink& AutomationDeviceLink::operator=(const AutomationDeviceLink& m)
{
	if (this == &m) return *this; // same object?

	(Automation&)*this = (const Automation&)m;



	return *this;
 }
 
bool AutomationDeviceLink::operator==(const AutomationDeviceLink &other) const
 {
	if ( (Automation&)*this != (const Automation&)other )
		return false;



	return true;
 }

//////////////////////////////////////////////////////////////////////////////////////////////// DEBUG & INFO
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////// SERIALIZATION

std::string AutomationDeviceLink::toString() const
 {
	return "";
 }

WRESULT AutomationDeviceLink::store( IEncoderWriter* serializer ) const {
	if ( serializer == NULL ) return WRET_ERR_PARAM;
	WRESULT ret = WRET_OK;
	return ret;
 }
WRESULT AutomationDeviceLink::retrieve( IEncoderReader* deserializer ) {
	if ( deserializer == NULL ) return WRET_ERR_PARAM;
	WRESULT ret = WRET_OK;
	return ret;
 }

/////////////////////////////////////////////////////////////////////////////////////////////// SERIALIZATION
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool DeviceTrigger::compare( const URI& event_source, const Fact* fact ) const
 {
	if ( fact == NULL ) return false;
	if ( this->source != event_source.getName() )
		return false;
	if ( this->event_name != fact->getEvent() )
		return false;
	if ( this->event_data.isEmpty() ) // means any value!
		return true;
	if ( !fact->hasData() ) {
		if ( this->event_data.isEmpty() )
			return true;
		return false;
	 }

	if ( fact->getData()->toString() ==  this->event_data.toString() )
		return true;
	return false;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

Message* DeviceEffect::generateMessage() const
 {
	 Request* request = new Request( this->method_name, this->method_arg.clone() );
	request->setOmitResponse(true);

	Message* msg_effect = new Message();
	msg_effect->setContent( request );
	msg_effect->getDestination().setKernelAny();
	msg_effect->getDestination().setName(this->target);
	return msg_effect;
 }


//////////////////////////////////////////////////////////////////////////////////////////////////////////////


 }; // namespace automations
}; // namespace wosh
